﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using Odyssey.Utils;
using System.Linq;
using System.Windows.Threading;
using Odyssey.Controls.Primitives;
using System.Windows.Media.Imaging;
using Odyssey.Behaviors;
using Odyssey.Controls.Models;

namespace Odyssey.Controls
{
    /// <summary>
    /// Panel used for ContextMenu.
    /// </summary>
    public class ContextMenu : Panel
    {
        public ContextMenu()
            : base()
        {
        }

        #region attached properties

        /// <summary>
        /// Gets  whether the context menu is open.
        /// </summary>
        public static bool GetIsOpen(DependencyObject obj)
        {
            return (bool)obj.GetValue(IsOpenProperty);
        }

        /// <summary>
        /// Sets whether the context menu is open.
        /// </summary>
        public static void SetIsOpen(DependencyObject obj, bool value)
        {
            obj.SetValue(IsOpenProperty, value);
        }

        public static readonly DependencyProperty IsOpenProperty =
            DependencyProperty.RegisterAttached("IsOpen", typeof(bool), typeof(ContextMenu), new PropertyMetadata(false, OnContextMenuOpenChanged));

        private static void OnContextMenuOpenChanged(DependencyObject o, DependencyPropertyChangedEventArgs args)
        {
            FrameworkElement element = o as FrameworkElement;
            if (element == null) throw new ArgumentNullException("Attached property IsOpen is only accepted on FrameworkElements.");

            bool isOpen = (bool)args.NewValue;
            if (!isOpen)
            {
                var cm = ContextMenuViewModel.Current;
                if (cm != null) cm.CloseContextMenu();
            }
            else
            {
                var template = ContextMenu.GetContextMenuTemplate(element);
                if (template != null)
                {
                    ContextMenuViewModel.TryOpenContextMenu(element, template);
                }
            }
        }                               

        /// <summary>
        /// Gets the DataTemplate of the context menu to open. This usually contais a ContextMenu panel including up to 5 ContextMenuItems.
        /// </summary>
        public static DataTemplate GetContextMenuTemplate(DependencyObject obj)
        {
            return (DataTemplate)obj.GetValue(ContextMenuTemplateProperty);
        }

        /// <summary>
        /// Sets the DataTemplate of the context menu to open. This usually contais a ContextMenu panel including up to 5 ContextMenuItems.
        /// </summary>
        public static void SetContextMenuTemplate(DependencyObject obj, DataTemplate value)
        {
            obj.SetValue(ContextMenuTemplateProperty, value);
        }

        public static readonly DependencyProperty ContextMenuTemplateProperty =
            DependencyProperty.RegisterAttached("ContextMenuTemplate", typeof(DataTemplate), typeof(ContextMenu), new PropertyMetadata(null, OnContextMenuTemplateChanged));

        private static void OnContextMenuTemplateChanged(DependencyObject o, DependencyPropertyChangedEventArgs args)
        {
            DataTemplate template = args.NewValue as DataTemplate;
            FrameworkElement element = o as FrameworkElement;
            if (element != null && template != null)
            {
                AttachMenuEvents(element);
            }
        }

        #endregion
        #region properties


        /// <summary>
        /// Gets or sets the height for each ContextMenuItem. The default value is 64.0
        /// </summary>
        public double ItemHeight
        {
            get { return (double)GetValue(ItemHeightProperty); }
            set { SetValue(ItemHeightProperty, value); }
        }

        public static readonly DependencyProperty ItemHeightProperty =
            DependencyProperty.Register("ItemHeight", typeof(double), typeof(ContextMenu), new PropertyMetadata(64.0));

        #endregion
        #region methods

        private static void AttachMenuEvents(FrameworkElement element)
        {
            //GestureService.GetGestureListener(element).Hold += (s,e) =>
            //    {
            //        SetIsOpen(element, true);
            //    };
            element.ManipulationStarted += new EventHandler<ManipulationStartedEventArgs>(HandleManipulationStarted);
        }

        static void HandleManipulationStarted(object sender, ManipulationStartedEventArgs e)
        {
            FrameworkElement element = sender as FrameworkElement;
            DataTemplate menuTemplate = GetContextMenuTemplate(element);
            ContextMenuViewModel viewModel = new ContextMenuViewModel(element, menuTemplate);
            viewModel.StartTimer();
        }


        protected override Size MeasureOverride(Size availableSize)
        {

            if (double.IsInfinity(availableSize.Width) || double.IsInfinity(availableSize.Height))
            {
                return base.MeasureOverride(availableSize);
            }
            else
            {
                int n = Math.Min(Children.Count, 5);
                double h = ItemHeight;
                Size size = new Size(availableSize.Width, h);
                for (int i = 0; i < n; i++)
                {
                    UIElement child = Children[i];
                    child.Measure(size);
                }
                n = RoundItems(n);
                availableSize.Height = n * h;
                return availableSize;
            }
        }

        private static int RoundItems(int n)
        {
            switch (n)
            {
                case 0: return 0;
                case 1: return 1;
                case 2:
                case 3: return 3;
                default: return 5;
            }
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            int n = Math.Min(Children.Count, 5);
            double h = ItemHeight;
            Rect rect = new Rect(0.0, 0.0, finalSize.Width, h);
            for (int i = 0; i < n; i++)
            {
                UIElement child = Children[i];
                child.Arrange(rect);
                rect.Y += h;
            }
            n = RoundItems(n);
            return new Size(finalSize.Width, n * ItemHeight);
        }

        #endregion
    }
}
